<?php

/* 
 * 微信支付
 * @author wyb
 */
namespace app\common\extend\pay;
class WxPay {
    
    private $_url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
    private $_appid = 'wx4ab1121dc0918be8'; //应用ID
    private $_appsecret = 'd44ec738684fb7f6c295dca4bf9b88cf';
    private $_mch_id = '1531595541'; //支付商户号
    private $_data = []; //数据集合
    private $_notify_url = 'http://m.enfukeji.com/notice.php/task/notify/order/type/wxpay';
    private $_appcliect_cart = '';
	private $_appcliect_key = '';
    public function __construct() {
        $this->_data = [
            'appid' => $this->_appid,
            'mch_id' => $this->_mch_id,
            'nonce_str' => $this->_nonceStr(), //随机字符串
        ];
		$this->_appcliect_cart = dirname(__FILE__).'/weixin/apiclient_cert.pem';
		$this->_appcliect_key = dirname(__FILE__).'/weixin/apiclient_key.pem';
    }
    
    /**
     * 生成支付字符串
     * @param type $order_info
     */
    public function pay( $order_info ) {

        $this->_data['trade_type'] = 'APP';

        $order_data = [
            'body'  => $order_info['body'],
            'out_trade_no'  => $order_info['order_sn'],
            'total_fee' => $order_info['total_price'] * 100,
            'spbill_create_ip'  => $this->_get_client_ip(),
            'notify_url' => $this->_notify_url,
            'attach' => $order_info['order_type']
        ];
        $this->_data = array_merge( $this->_data , $order_data );
        $this->_sign();
        $result = $this->_getData();
        $getData = (array)simplexml_load_string($result, 'SimpleXMLElement', LIBXML_NOCDATA);
        if( !$getData || $getData['return_code'] == 'FAIL' || ($getData['return_code'] == 'SUCCESS' && $getData['result_code'] == 'FAIL') ) {
            return [ 'msg' => '支付异常，请联系客服！' , 'status' => false ];
        } else {
            $new_sign = [
                'appid' => $this->_appid,
                'partnerid' => $this->_mch_id,
                'prepayid'  => $getData['prepay_id'],
                'noncestr'  => $this->_nonceStr(),
                'timestamp' => time(),
                'package'   => 'Sign=WXPay',
            ];
            $this->_data = $new_sign;
            $this->_sign();
            $datas = [
                'appid' => $this->_data['appid'],
                'noncestr' => $this->_data['noncestr'],
                'package' => $this->_data['package'],
                'partnerid' => $this->_data['partnerid'],
                'prepayid' => $this->_data['prepayid'],
                'timestamp' => $this->_data['timestamp'],
                'sign'  => $this->_data['sign']
            ];
            return [ 'msg' => '成功' ,'data' => $datas , 'status' => true ];
        }
    }
    
    /**
     * function：订单支付完成后回写数据库(微信支付回调)
     * @return json
     */
    public function notify(){
        $postStr  = $GLOBALS["HTTP_RAW_POST_DATA"];
        $getData = (array)simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
        //判断支付成功
        if( $getData['return_code'] == "SUCCESS" && $getData['result_code'] == 'SUCCESS' && $getData['appid'] == $this->_appid && $getData['mch_id'] == $this->_mch_id) {
            //签名验证
            $this->_data = $getData;
            unset( $this->_data['sign'] );
            $this->_sign();
            if( $this->_data['sign'] == $getData['sign'] ) {
				if( !$getData['out_trade_no'] ) return false;
				$this->_data = [
					'return_code' => '<![CDATA[SUCCESS]]>',
					'return_msg'  => '<![CDATA[OK]]>'
				];
				echo $this->_xmlData();
				return [
					'ordersn' => $getData['out_trade_no'],
					'type' => $getData['attach'],
					'trade_no' => $getData['transaction_id'],
					'price' => $getData['total_fee'] / 100
				];
			}
		}
		$this->_data = [
			'return_code' => '<![CDATA[FAIL]]>',
			'return_msg'  => '<![CDATA[error]]>'
		];
		echo $this->_xmlData();
		return false;
    }

    /**
     * 订单退款
     */
    public function orderRefund( $order_data ) {
        $this->_url = 'https://api.mch.weixin.qq.com/secapi/pay/refund';
        //退款数据
        $refund_data = [
            'out_trade_no' => $order_data['order_sn'],
            'out_refund_no' => $order_data['order_sn'],
            'total_fee' => $order_data['total_price'] * 100,
            'refund_fee' => $order_data['refund_fee'] * 100,
            'op_user_id' => $this->_mch_id,
            'refund_account' => 'REFUND_SOURCE_RECHARGE_FUNDS'
        ];
        $this->_data = array_merge( $this->_data , $refund_data );
        $this->_sign();
        $result = $this->_getData( 2 );
        $getData = (array)simplexml_load_string($result, 'SimpleXMLElement', LIBXML_NOCDATA);
        if( !$result || !$getData || $getData['return_code'] == 'FAIL' ) {
            return [ 'msg' => '支付异常，请联系客服！' , 'status' => false ];
        } else if(  $getData['result_code'] == 'FAIL' ) {
            return [ 'msg' => "code：". $getData['err_code'] . " 错误描述：".$getData['err_code_des'] , 'status' => false ];
        } else {
            return [ 'msg' => '退款成功' , 'status' => true ];
        }
    }

    /**
     * 退款查询
     */
    public function refundQuery( $order_data ) {
        $this->_url = 'https://api.mch.weixin.qq.com/pay/refundquery';
        //查询数据
        $query_data = array(
            'out_trade_no' => $order_data['order_sn']
        );

        $this->_data = array_merge( $this->_data , $query_data );
        $this->_sign();
        $result = $this->_getData();
        $getData = (array)simplexml_load_string($result, 'SimpleXMLElement', LIBXML_NOCDATA);
        if( $getData['return_code'] == 'SUCCESS' ) {
            //退款成功
            if( $getData['result_code'] == 'SUCCESS' ) {
                return true;
            }
        }
		return false;
    }

    /**
     * 支付查询
     */
    public function orderQuery( $order_data ) {
		$this->_url = 'https://api.mch.weixin.qq.com/pay/orderquery';
		//查询数据
        $query_data = array(
            'out_trade_no' => $order_data['order_sn']
        );

        $this->_data = array_merge( $this->_data , $query_data );
        $this->_sign();
        $result = $this->_getData();
        $getData = (array)simplexml_load_string($result, 'SimpleXMLElement', LIBXML_NOCDATA);
        if( $getData['return_code'] == 'SUCCESS' ) {
            //退款成功
            if( $getData['result_code'] == 'SUCCESS' ) {
				if( $getData['trade_state'] == 'SUCCESS' ){
					return true;
				}
            }
        }
		return false;
	}
    /**
     * 生成xml
     * @return string
     */
    private function _xmlData() {
        $xml_data = "<xml>";
        foreach( $this->_data as $key => $value ) {
            $xml_data .= "<$key>$value</$key>";
        }
        $xml_data .= "</xml>";
        return $xml_data;
    }
    
    /**
     * 签名价签
     */
    private function _sign() {
        ksort( $this->_data );
        reset( $this->_data );
        $sign_data = [];
        foreach( $this->_data as $key => $value ) {
            if( $value != '' ) {
                $sign_data[] = "$key=$value";
            }
        }
        $sign_data = implode('&' , $sign_data ) . "&key=".$this->_appsecret;
        $this->_data['sign'] = strtoupper( md5( $sign_data ) );
    }
    
    /**
    * 获取客户端IP地址
    * @param integer $type 返回类型 0 返回IP地址 1 返回IPV4地址数字
    * @param boolean $adv 是否进行高级模式获取（有可能被伪装） 
    * @return mixed
    */
    private function _get_client_ip($type = 0,$adv=false) {
       $type       =  $type ? 1 : 0;
       static $ip  =   NULL;
       if ($ip !== NULL) return $ip[$type];
       if($adv){
           if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
               $arr    =   explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
               $pos    =   array_search('unknown',$arr);
               if(false !== $pos) unset($arr[$pos]);
               $ip     =   trim($arr[0]);
           }elseif (isset($_SERVER['HTTP_CLIENT_IP'])) {
               $ip     =   $_SERVER['HTTP_CLIENT_IP'];
           }elseif (isset($_SERVER['REMOTE_ADDR'])) {
               $ip     =   $_SERVER['REMOTE_ADDR'];
           }
       }elseif (isset($_SERVER['REMOTE_ADDR'])) {
           $ip     =   $_SERVER['REMOTE_ADDR'];
       }
       // IP地址合法验证
       $long = sprintf("%u",ip2long($ip));
       $ip   = $long ? array($ip, $long) : array('0.0.0.0', 0);
       return $ip[$type];
   }
   
   /**
    * 随机字符串
    */
   private function _nonceStr(){
       $str = 'ABCDEF1234567890GHIJKLMNOPQRSTUVWXYZ1234567890';
       $str_data = '';
       $strlen = strlen( $str );
       for( $i=1; $i<=32; $i++ ) {
           $str_data .= $str[rand(0,$strlen-1)];
       }
       return $str_data;
   }
   
   /**
     * 发送请求
     */
    private function _getData( $is_refound = 1 ) {
		$data = $this->_xmlData( $this->_data );
        $ci = curl_init();
        curl_setopt( $ci, CURLOPT_URL, $this->_url);
        curl_setopt($ci,CURLOPT_TIMEOUT, 30 );
        curl_setopt($ci,CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ci,CURLOPT_SSL_VERIFYPEER,false);
        curl_setopt($ci,CURLOPT_SSL_VERIFYHOST,false);
        if( $is_refound == 2 ) {
            curl_setopt($ci,CURLOPT_SSLCERT, $this->_appcliect_cart);
            curl_setopt($ci,CURLOPT_SSLKEY, $this->_appcliect_key);
        }
        curl_setopt( $ci, CURLOPT_HTTPHEADER, array( "Content-type: text/xml" ));
        curl_setopt( $ci, CURLOPT_POST, 1);
        curl_setopt( $ci, CURLOPT_POSTFIELDS,  $data );
        if( curl_errno( $ci ) ){
            print curl_error($ci);
        }
        $result = curl_exec( $ci );
        $status = curl_getinfo( $ci );
        curl_close($ci);
        return $result;
    }
}

